package _8nio;

import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @description:
 * @author: wang zhen
 * @create: 2022-07-28 14:41
 */
public class SelectorTest {


    @Test
    public void server() {


        ServerSocketChannel server1 = null;
        ServerSocketChannel server2 = null;
        ServerSocketChannel server3 = null;
        Selector selector=null;
        try {

            //创建三个ServerSocketChannel监听三个端口
            server1 = ServerSocketChannel.open();
            server2 = ServerSocketChannel.open();
            server3 = ServerSocketChannel.open();

            server1.bind(new InetSocketAddress("127.0.0.1", 7777));
            server2.bind(new InetSocketAddress("127.0.0.1", 8888));
            server3.bind(new InetSocketAddress("127.0.0.1", 9999));

            //设置非阻塞
            server1.configureBlocking(false);
            server2.configureBlocking(false);
            server3.configureBlocking(false);


            //将三个ServerSocketChannel注册到Selector
            selector = Selector.open();
            server1.register(selector, SelectionKey.OP_ACCEPT);
            server2.register(selector, SelectionKey.OP_ACCEPT);
            server3.register(selector, SelectionKey.OP_ACCEPT);

            System.out.println("开始监听");
            while (true){

                selector.select();

                System.out.println("有连接进入");

                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()){

                    SelectionKey key = iterator.next();


                    if(key.isAcceptable()){
                        ServerSocketChannel serverSocketChannel=(ServerSocketChannel)key.channel();
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        socketChannel.configureBlocking(false);
                        InetSocketAddress address = (InetSocketAddress)socketChannel.getLocalAddress();

                        System.out.println("正在处理:"+address.getPort()+"端口的连接");
                        socketChannel.register(selector,SelectionKey.OP_READ);
                        iterator.remove();

                    }else if(key.isReadable()){
                        SocketChannel socketChannel=(SocketChannel)key.channel();
                        InetSocketAddress address = (InetSocketAddress)socketChannel.getLocalAddress();

                        System.out.println("正在读取:"+address.getPort()+"端口的数据");
                        ByteBuffer buffer=ByteBuffer.allocate(1024);
                        socketChannel.read(buffer);

                        System.out.println("打印每次读取的数据:" + new String(buffer.array()));

                        //确定读取后不会写入，那么将连接关闭并删除
                        socketChannel.close();
                        iterator.remove();
                    }



                }

            }



        } catch (Exception e) {
            e.printStackTrace();

        } finally {

            try {
                if (selector != null) {
                    selector.close();
                }
                if (server1 != null) {
                    server1.close();
                }
                if (server2 != null) {
                    server2.close();
                }
                if (server3 != null) {
                    server3.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }


    @Test
    public void client() {

        Socket socket = null;
        OutputStream outputStream = null;
        InputStream inputStream = null;
        try {
            //1.创建客户端对象，并指定连接的IP地址或主机名+端口号
            socket = new Socket("127.0.0.1", 9999);

            //2.获取这个通道的流，输出数据到通道中
            outputStream = socket.getOutputStream();

            //3.发送数据
            outputStream.write("你好".getBytes());
            socket.shutdownOutput();//通过shutdownOutput高速服务器已经发送完数据，后续只能接受数据


        } catch (Exception e) {
            e.printStackTrace();

        } finally {

            //5.关闭资源
            try {
                if (inputStream != null) {
                    inputStream.close();
                }

                if (outputStream != null) {
                    outputStream.close();
                }

                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
